package org.xhy;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.matcher.ElementMatchers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.named;


/**
 * -javaagent:/Users/xhy/IdeaProjects/xhy-skywalking/study-agent-springmvc/target/study-agent-springmvc-1.0-SNAPSHOT-jar-with-dependencies.jar
 */

public class MyAgent {
    private static final String CONTROLLER_NAME = "org.springframework.stereotype.Controller";
    private static final String REST_CONTROLLER_NAME = "org.springframework.web.bind.annotation.RestController";
    private static final Logger log = LoggerFactory.getLogger(MyAgent.class);

    public static void premain(String args, Instrumentation instrumentation) {
        // premain 方法是 Java Agent 的入口方法
        // 在主应用启动之前，JVM 会调用该方法
        // args 是启动时传递给 Agent 的参数，instrumentation 是 Java 提供的 Instrumentation API 对象，
        // 用来操控和修改 JVM 中的类（比如通过类转换器拦截类加载过程）

        log.info("进入 premain");
        // 记录日志，表示 Agent 的 premain 方法已被调用，Agent 开始工作

        // 创建一个新的 AgentBuilder 对象，用于定义类转换的规则
        // AgentBuilder.Default() 是 Byte Buddy 提供的用于创建类转换规则的起始点
        AgentBuilder builder = new AgentBuilder.Default()
                // 定义要拦截的类类型，这里使用 isAnnotatedWith 方法来匹配被特定注解标记的类
                // named(CONTROLLER_NAME) 和 named(REST_CONTROLLER_NAME) 是匹配特定类名（或注解名）
                // CONTROLLER_NAME 和 REST_CONTROLLER_NAME 可能是常量，表示 Spring 中的 @Controller 和 @RestController 注解的类
                // 这个条件是：匹配被 @Controller 或 @RestController 注解标记的类
                .type(isAnnotatedWith(named(CONTROLLER_NAME).or(named(REST_CONTROLLER_NAME))))

                // transform 方法定义如何转换匹配到的类，AgentTransformer 是一个自定义的类转换器
                // 这个转换器负责在类加载时修改类的字节码（比如增强方法或修改类行为）
                .transform(new AgentTransformer());

        // 安装 AgentBuilder 到 Instrumentation 对象上
        // 这一步将定义的类转换规则应用到 JVM 中，使得当匹配的类被加载时，AgentTransformer 会对它们进行字节码修改
        builder.installOn(instrumentation);
    }

}
